home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Amiga Plus 2000 #5
/
Amiga Plus CD - 2000 - No. 5.iso
/
Tools
/
Dev
/
Real
/
dither.c
< prev
next >
Wrap
C/C++ Source or Header
|
1999-07-31
|
8KB
|
309 lines
/*
* Copyright (c) 1997 Miloslaw Smyk
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by Miloslaw Smyk
* 4. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#define REVISION "40.2"
#define AUTHOR "Miloslaw Smyk"
#define VERNUM 40
#define REVNUM 2
#define DT_FS 0
#define DT_ORDERED 1
#define DT_NONE 2
/* some useful includes */
#include <string.h>
int dither_type = DT_NONE;
struct R3DHandle
{
UBYTE depth;
UWORD size_x, size_y;
SHORT *line;
int line_width;
};
/*
** 4x4 4-bit dispersed dot ordered dither pattern, which is the base
** for final dither pattern, calculated as soon as screen depth
** is known.
*/
const UBYTE dithBase[4][4] = {
1, 15, 2, 12,
9, 5, 10, 7,
3, 13, 0, 14,
11, 7, 8, 4
};
static struct dith
{
UBYTE r, g, b, g2;
} dith[4][4];
struct dither_val
{
UBYTE r[2], g[2], b[2], g2[2];
} dither[256];
int red5[256], green5[256], blue5[256], green6[256];
enum {COL_ORIGINAL, COL_SHIFTED};
/* macros we use to get fractions with integer math */
#define SCALING_FACTOR 4
#define HALF 8
#define DESCALE(expr) (((expr) + HALF) >> SCALING_FACTOR)
void LIBInitDithering(void)
{
int i,j;
/* calculate errors for every possible pixel value. */
for(i = 0; i < 256; i++)
{
red5[i] = i - ((i + 4) & ~0x07);
green5[i] = i - ((i + 4) & ~0x07);
green6[i] = i - ((i + 2) & ~0x03);
blue5[i] = i - ((i + 4) & ~0x07);
}
for(i = 0; i < 256; i++)
{
dither[i].r[COL_ORIGINAL] = i & ~0x07;
dither[i].g[COL_ORIGINAL] = i & ~0x07;
dither[i].g2[COL_ORIGINAL] = i & ~0x03;
dither[i].b[COL_ORIGINAL] = i & ~0x07;
dither[i].r[COL_SHIFTED] = MIN(i + 8, 255);
dither[i].g[COL_SHIFTED] = MIN (i + 8, 255);
dither[i].g2[COL_SHIFTED] = MIN(i + 4,255);
dither[i].b[COL_SHIFTED] = MIN(i + 8, 255);
}
for(j = 0; j < 4; j++)
for(i = 0; i < 4; i++)
{
dith[i][j].r = (dithBase[i][j] * 16) / 32;
dith[i][j].g = (dithBase[i][j] * 16) / 32;
dith[i][j].g2 = (dithBase[i][j] * 16) / 64;
dith[i][j].b = (dithBase[i][j] * 16) / 32;
}
}
void LIBDitherLine(struct R3DHandle *handle, UBYTE *buf, int len, int x, int y)
{
int i;
int bsame_r, bnext_r, next_r;
int bsame_g, bnext_g, next_g;
int bsame_b, bnext_b, next_b;
UBYTE *inptr;
SHORT *errptr;
int delta;
int temp;
if(handle->depth == 15 || handle->depth == 16)
{
switch(dither_type)
{
case DT_FS:
if(handle->line_width != len)
{
if(handle->line)
FreeVec(handle->line);
handle->line = AllocVec(sizeof(SHORT) * (len + 2) * 3, MEMF_ANY | MEMF_CLEAR);
handle->line_width = len;
}
inptr = buf;
errptr = handle->line + 3;
/* make sure there is no error at the start of the line */
for(i = 0; i < 3; i++)
errptr[i] = 0;
bsame_r = bnext_r = next_r = 0;
bsame_g = bnext_g = next_g = 0;
bsame_b = bnext_b = next_b = 0;
for(i = 0; i < len; i++)
{
/* red component */
temp = *inptr + DESCALE(next_r + bsame_r);
if(temp < 0)
*inptr = 0;
else
if(temp > 255)
*inptr = 255;
else
*inptr = temp;
/* right-down pixel gets 1/16 of error */
bnext_r = red5[*inptr];
delta = bnext_r << 1;
/* left-down pixel gets 3/16 of error */
next_r = bnext_r + delta;
*(errptr - 3) += next_r;
/* pixel below gets 5/16 of error */
next_r += delta;
*errptr += next_r;
/* next pixel (to the right) gets 7/16 of error */
next_r += delta;
/* try to get closest match with color-gun */
if(*inptr < 252)
*inptr += 4;
bsame_r = *(errptr);
*(errptr) = bnext_r;
errptr++;
inptr++;
/* green component */
temp = *inptr + DESCALE(next_g + bsame_g);
if(temp < 0)
*inptr = 0;
else
if(temp > 255)
*inptr = 255;
else
*inptr = temp;
/* right-down pixel gets 1/16 of error */
bnext_g = handle->depth == 15 ? green5[*inptr] : green6[*inptr];
delta = bnext_g << 1;
/* left-down pixel gets 3/16 of error */
next_g = bnext_g + delta;
*(errptr - 3) += next_g;
/* pixel below gets 5/16 of error */
next_g += delta;
*errptr += next_g;
/* next pixel (to the right) gets 7/16 of error */
next_g += delta;
/* try to get closest match with color-gun */
if(handle->depth == 15)
{
if(*inptr < 252)
*inptr += 4;
}
else
{
if(*inptr < 254)
*inptr += 2;
}
bsame_g = *(errptr);
*(errptr) = bnext_g;
errptr++;
inptr++;
/* blue component */
temp = *inptr + DESCALE(next_b + bsame_b);
if(temp < 0)
*inptr = 0;
else
if(temp > 255)
*inptr = 255;
else
*inptr = temp;
/* right-down pixel gets 1/16 of error */
bnext_b = blue5[*inptr];
delta = bnext_b << 1;
/* left-down pixel gets 3/16 of error */
next_b = bnext_b + delta;
*(errptr - 3) += next_b;
/* pixel below gets 5/16 of error */
next_b += delta;
*errptr += next_b;
/* next pixel (to the right) gets 7/16 of error */
next_b += delta;
/* try to get closest match with color-gun */
if(*inptr < 252)
*inptr += 4;
bsame_b = *(errptr);
*(errptr) = bnext_b;
errptr++;
/* advance input pointer */
inptr += 2;
}
break;
case DT_ORDERED:
if(handle->depth == 15)
for(i = 0; i < len * 4; i += 4)
{
if(buf[i] - dither[buf[i]].r[COL_ORIGINAL] > dith[y & 3][(i / 4) & 3].r)
buf[i] = dither[buf[i]].r[COL_SHIFTED];
if(buf[i + 1] - dither[buf[i + 1]].g[COL_ORIGINAL] > dith[y & 3][(i / 4) & 3].g)
buf[i + 1] = dither[buf[i + 1]].g[COL_SHIFTED];
if(buf[i + 2] - dither[buf[i + 2]].b[COL_ORIGINAL] > dith[y & 3][(i / 4) & 3].b)
buf[i + 2] = dither[buf[i + 2]].b[COL_SHIFTED];
}
else
for(i = 0; i < len * 4; i += 4)
{
if(buf[i] - dither[buf[i]].r[COL_ORIGINAL] > dith[y & 3][(i / 4) & 3].r)
buf[i] = dither[buf[i]].r[COL_SHIFTED];
if(buf[i + 1] - dither[buf[i + 1]].g2[COL_ORIGINAL] > dith[y & 3][(i / 4) & 3].g2)
buf[i + 1] = dither[buf[i + 1]].g2[COL_SHIFTED];
if(buf[i + 2] - dither[buf[i + 2]].b[COL_ORIGINAL] > dith[y & 3][(i / 4) & 3].b)
buf[i + 2] = dither[buf[i + 2]].b[COL_SHIFTED];
}
break;
}
}
}